package com.example.service;

import cn.hutool.core.util.StrUtil;
import com.baidu.aip.imageclassify.AipImageClassify;
import com.example.common.PageResult;
import com.example.common.enums.ErrorCodeEnum;
import com.example.exception.CustomException;
import com.example.pojo.dto.PetQueryDto;
import com.example.pojo.entity.Pet;
import com.example.pojo.vo.PetQueryVo;
import com.example.pojo.vo.PetRecognitionVo;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.*;

/**
 *  宠物识别 service 层实现类
 */
@Service
public class PetRecognizeServiceImpl implements PetRecognizeService{

    @Value("${baidu.ai.app-id}")
    private String APP_ID;

    @Value("${baidu.ai.api-key}")
    private String API_KEY;

    @Value("${baidu.ai.secret-key}")
    private String SECRET_KEY;

    // 单例的百度AI客户端
    private AipImageClassify aipImageClassify;

    @Resource
    private PetService petService;

    @PostConstruct
    public void init() {
        // 创建百度AI客户端
        this.aipImageClassify = new AipImageClassify(this.APP_ID, this.API_KEY, this.SECRET_KEY);
    }

    /**
     * 识别图片中的宠物
     *
     * @param image 图片
     * @return 识别结果数组
     * @throws IOException io异常
     */
    @Override
    public List<PetRecognitionVo> petRecognize(MultipartFile image) throws IOException {
        // 1.校验参数
        if (image == null || image.isEmpty()) {
            throw new CustomException(ErrorCodeEnum.IMAGE_IS_NULL);
        }

        // 2.调用百度AI接口
        JSONObject recognizeResultJSON = aipImageClassify.animalDetect(image.getBytes(), new HashMap<>());

        // 3.解析结果
        List<PetRecognitionVo> voList = new ArrayList<>();
        if (recognizeResultJSON.has("result")) {
            JSONArray resultArray = recognizeResultJSON.getJSONArray("result");
            for (int i = 0; i < resultArray.length(); i++) {
                JSONObject jsonObject = resultArray.getJSONObject(i);
                PetRecognitionVo vo = new PetRecognitionVo();
                vo.setName(jsonObject.getString("name"));
                vo.setScore(jsonObject.getDouble("score"));
                voList.add(vo);
            }
        } else {
            throw new CustomException(ErrorCodeEnum.BAIDU_API_RESULT_ERROR);
        }

        // 4.按置信度从大到小排序
        voList = voList.stream().sorted(Comparator.comparing(PetRecognitionVo::getScore, Comparator.reverseOrder())).toList();

        // 5.返回识别结果数组
        return voList;
    }

    /**
     * 识别图片中的宠物，并根据识别结果分页查询宠物
     *
     * @param pageNum 页码
     * @param pageSize 页大小
     * @param image 图片
     * @return 分页结果
     * @throws IOException io异常
     */
    @Override
    public PageResult<PetQueryVo> petPageQueryByImage(Integer pageNum, Integer pageSize, MultipartFile image) throws IOException {
        // 1.没有上传图片，则分页查询
        if (image == null || image.isEmpty()) {
            return this.petService.pageQuery(pageNum, pageSize, null);
        }

        // 2.调用百度api识别图片中的宠物，返回结果按置信度从大到小排序
        List<PetRecognitionVo> voList = this.petRecognize(image);

        // 3.生成候选搜索关键词
        Set<String> candidateKeys = new LinkedHashSet<>();
        for (PetRecognitionVo vo : voList) {
            // 3.1 生成侯选关键词
            candidateKeys.addAll(generateSearchKeys(vo.getName()));
            // 3.2 置信度低于 0.3 终止
            if (vo.getScore() < 0.3) {
                break;
            }
        }

        // 4.根据候选搜索关键词，生成关键词
        String key = getKey(candidateKeys);

        // 5.key是最终关键词，分页查询宠物
        if (StrUtil.isNotBlank(key)) {
            // 5.1 有关键词，根据关键词分页查询宠物
            return executePageQuery(pageNum, pageSize, key);
        } else {
            // 6.2 没有关键词，返回空数据
            return new PageResult<>(0L, Collections.emptyList());
        }
    }

    /**
     * 根据原名称，生成候选搜索关键词
     *
     * @param originName 原名称
     * @return 候选搜索关键词列表
     */
    private List<String> generateSearchKeys(String originName) {
        List<String> keys = new ArrayList<>();

        // 1.原始名称加入关键词列表
        keys.add(originName);

        // 2.逐步缩短
        String temp = originName;
        while (temp.length() > 1) {
            temp = temp.substring(1);
            keys.add(temp);
        }

        // 3.返回候选搜索关键词列表
        return keys;
    }


    /**
     * 根据候选搜索关键词，逐个去查询数据库，看是否查询到数据，有则生成关键词
     *
     * @param candidateKeys 候选搜索关键词
     * @return 关键词
     */
    private String getKey(Set<String> candidateKeys) {
        for (String key : candidateKeys) {
            if (this.petService.lambdaQuery().like(Pet::getName, key).count() > 0) {
                return key;
            }
        }
        return null;
    }

    /**
     * 执行分页查询
     *
     * @param pageNum 页码
     * @param pageSize 页大小
     * @param keyword 关键词
     * @return 分页结果
     */
    private PageResult<PetQueryVo> executePageQuery(Integer pageNum, Integer pageSize, String keyword) {
        PetQueryDto dto = new PetQueryDto();
        dto.setName(keyword);
        return petService.pageQuery(pageNum, pageSize, dto);
    }
}
